#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/mm.h>
#include <linux/mm_types.h>

/**
 * @brief 内核模块初始化函数
 * 
 * 模块加载时调用此函数，打印当前任务的内核栈和用户栈的起始地址及大小。
 * 
 * @return int 成功返回0
 */
static int __init stack_info_init(void)
{
    struct task_struct *task = current; // 获取当前任务的 task_struct 结构
    unsigned long kernel_stack_size = THREAD_SIZE; // 获取内核栈大小，通常在 x86_64 架构中为 8192 字节 (8KB)

    // 打印内核栈的起始地址和大小
    printk(KERN_INFO "Kernel Stack Start: %lx\n", (unsigned long)task->stack);
    printk(KERN_INFO "Kernel Stack Size: %lu bytes\n", kernel_stack_size);

    if (task->mm) { // 确保当前任务有 mm_struct，表示是用户进程
        struct vm_area_struct *vma;
        // 遍历任务的虚拟内存区域
        for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
            if (vma->vm_flags & VM_STACK) { // 检查该区域是否为用户栈
                // 打印用户栈的起始地址和大小
                printk(KERN_INFO "User Stack Start: %lx\n", (unsigned long)task->mm->start_stack);
                printk(KERN_INFO "User Stack Size: %lu bytes\n", vma->vm_end - vma->vm_start);
                break;
            }
        }
    } else {
        // 打印信息说明没有用户栈，可能是内核线程或已换出的进程
        printk(KERN_INFO "No user stack (kernel thread or swapped out process).\n");
    }

    return 0; ///< 返回初始化成功
}

/**
 * @brief 内核模块清理函数
 * 
 * 模块卸载时调用此函数，打印退出日志信息。
 */
static void __exit stack_info_exit(void)
{
    printk(KERN_INFO "Stack info module exited.\n"); ///< 打印模块卸载信息
}

module_init(stack_info_init); ///< 指定模块初始化函数
module_exit(stack_info_exit); ///< 指定模块退出函数

MODULE_LICENSE("GPL"); ///< 指定模块许可证为GPL
MODULE_DESCRIPTION("Print stack start address and size for current task"); ///< 模块描述
MODULE_AUTHOR("Zhenxiong Chen"); ///< 模块作者
